All files / src/app/collections/[id]/members page.tsx

45.45% Statements 5/11
50% Branches 1/2
50% Functions 1/2
50% Lines 5/10

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52                                  1x 1x 1x       1x     1x                                                  
import { getSession } from "@/lib/auth";
import { redirect } from "next/navigation";
import { getDb } from "@/lib/db";
import { requireCollectionOwnerPage } from "@/lib/collection-access";
import { MemberController } from "@/server/api/members";
import { InvitationController } from "@/server/api/invitations";
import { AppLayout } from "@/components/layout";
import { trail } from "@/components/layout/breadcrumb-trails";
import { Card } from "@/components/ui";
import { MemberList } from "@/features/collections/MemberList";
import { InviteForm } from "@/features/collections/InviteForm";
 
interface MembersPageProps {
  params: Promise<{ id: string }>;
}
 
export default async function MembersPage({ params }: MembersPageProps) {
  const { id } = await params;
  const session = await getSession();
  Iif (!session?.user) {
    redirect("/login");
  }
 
  const db = getDb();
  // Owner-only page: members:manage = owner by role (purses-yqw). The owner gate
  // also covers the invitee-email PII surfaced by the pending rows below.
  const collection = await requireCollectionOwnerPage(db, id, session.user.id);
 
  const members = await MemberController.fromDb(db).listMembers(collection.id);
  const invitations = await InvitationController.fromDb(db).listByCollection(collection.id);
  const pending = invitations.filter((i) => i.status === "pending");
 
  return (
    <AppLayout breadcrumbs={trail.members(collection)}>
      <div className="space-y-8">
        <div className="space-y-2">
          <h1 className="text-2xl text-ink sm:text-3xl">People</h1>
          <p className="max-w-2xl text-ink-soft">
            Sharing is an after-the-fact step — invite someone once your list feels ready.
          </p>
        </div>
 
        <Card padding="lg">
          <InviteForm collectionId={collection.id} />
        </Card>
 
        <MemberList members={members} pending={pending} canManage />
      </div>
    </AppLayout>
  );
}